// Copyright 2022 jeff.li. and/or its affiliates.


#include <tbir/runtime/container.h>
#include <tbir/runtime/container_private.h>
#include <tbir/runtime/ft_container.h>
#include <tbir/runtime/registry.h>

namespace tbir::runtime {

    /******************************************************************************
     * Tuple container
     *****************************************************************************/
    TBIR_REGISTER_GLOBAL("runtime.GetTupleSize").set_body([](PyArgs args) -> RTValue {
        const auto &tup = args[0].As<Tuple>();
        return static_cast<int64_t>(tup.size());
    });

    TBIR_REGISTER_GLOBAL("runtime.GetTupleFields").set_body([](PyArgs args) -> RTValue {
        int64_t idx = args[1].As<int64_t>();
        const auto &tup = args[0].As<Tuple>();
        MXCHECK_LT(idx, tup.size());
        return tup[idx];
    });

    TBIR_REGISTER_GLOBAL("runtime.Tuple").set_body([](PyArgs args) -> RTValue {
        std::vector<RTValue> fields;
        fields.reserve(args.size());
        for (auto i = 0; i < args.size(); ++i) {
            fields.push_back(args[i].As<RTValue>());
        }
        return Tuple(std::make_move_iterator(fields.begin()), std::make_move_iterator(fields.end()));
    });

    TBIR_REGISTER_GLOBAL("runtime.TupleEqual").set_body([](PyArgs args) -> RTValue {
        MXCHECK(2 == args.size()) << "tuple.__eq__ expect " << 2 << " arguments but get " << args.size();
        const auto &self = args[0];
        const auto &other = args[1];
        switch (self.type_code()) {
            case TypeIndex::kRuntimeTuple: {
                if (other.IsObjectRef<Tuple>()) {
                    return self.AsObjectRefNoCheck<Tuple>() == other.AsObjectRefNoCheck<Tuple>();
                }
            }
                break;
            default: {
                MXTHROW << "expect 'tuple' but get '" << self.type_name();
            }
                break;
        }
        return false;
    });

}  // namespace tbir::runtime
